///////////////////////////////////////////////////////////
//  Wobbly HLSL:
//  This is a pretty trivial shader.  Diffuse lighting is 
//  calculated, and the model surface is offset by a sine 
//  wave travelling through it.
//  It also tweens between two streams - in this case,
//  morphing the head model from one expression to another. 
///////////////////////////////////////////////////////////

//The annotation following the texture declaration allows
// my application code to automatically load & bind the texture.
texture diffuseTexture : Texture < string name = "face.tga"; >;
float4 tweenAmount;
float4 light1;
float4 light2;
float time;
float4 eyePos;
float4x4 world : World;
float4x4 worldViewProj : WorldViewProjection;

sampler Sampler = sampler_state
{
    Texture   = (diffuseTexture);
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
};

//Passed to the vertex shader from the pipeline
struct VS_INPUT
{
   float4 pos1 : POSITION0;
   float4 normal1 : NORMAL0;
   float2 texCoord1 : TEXCOORD0;
   
   float4 pos2 : POSITION1;
   float4 normal2 : NORMAL1;
   float2 texCoord2 : TEXCOORD1;
};  

//VS output / PS input:
struct VS_OUTPUT
{
    float4 pos : POSITION;
    float4 color : COLOR0;
    float2 texCoord : TEXCOORD0;
};

//PS output:
struct pixel
{
    float4 color : COLOR;
};

//////////////////////////
//  Handy functions:
//////////////////////////

// Tween the vertex position from the two streams,
float4 tweenPosition(float4 pos1, float4 pos2)
{
    return tweenAmount.x*pos1 + tweenAmount.y*pos2; 
}

// Tween the normal from the two streams.
float4 tweenNormal(float4 n1, float4 n2)
{
    return (tweenAmount.x*n1 + tweenAmount.y*n2);
}

//Generate diffuse lighting from normal & the global light directions
float4 lightDiffuse(float4 normal)
{
    return dot(normal, light1) + dot(normal, light2);
}

//////////////////////////
//  Vertex Shaders:
//////////////////////////
VS_OUTPUT vertexShader(VS_INPUT IN)
{
    VS_OUTPUT OUT;
    float4 tweenedPos = tweenPosition(IN.pos1, IN.pos2);
    OUT.pos = mul(tweenedPos, worldViewProj);
    
    float4 normal = tweenNormal(IN.normal1, IN.normal2);
    float4 normalScreen = normalize(mul(normal, world));

    //Wobble calculations:
    // The surface is offset in the direction of the surface normal, 
    // using some arbitary sine wave perturbations.
    OUT.pos += normalScreen * 0.05f*sin(IN.pos1.y*20 + IN.pos1.z*15 + 4*time);
    // This then affects the surface normal.  
    // I don't think this calculation is technically
    // correct, but it looks ok.  *shrug*
    //normal += normalScreen * 0.05f*cos(IN.pos1.y*20 + IN.pos1.z*15 + 4*time);

    // The diffuse color will get clamped from 0..1.  
    // This then gives some unpleasant saturation effects.  To minimise this,
    // we divide the color by 2 here, then multiply by 2 in the pixel shader.
    OUT.color = lightDiffuse(normal) * 0.5f;
    
    OUT.texCoord = IN.texCoord1;   
    
    return OUT;
}

//////////////////////////
//  Pixel Shaders:
//////////////////////////
pixel pixelShader(VS_OUTPUT IN)
{
    pixel OUT;
    float4 texSample = tex2D( Sampler, IN.texCoord ) + 0.05f;
    // Color is multiplied by two, since we halved it to 
    // avoid saturation in the vertex shader.	
    OUT.color.rgb = IN.color.rgb*texSample.rgb * 2.0f;
    OUT.color.a = 1.0f;
	
    return OUT;
}

//////////////////////////
//  Techniques:
//////////////////////////
technique T0
{
    // The annotation following the pass allows my application
    // to seperate the rendering process into stages, one for rendering to texture,
    // one for overlaying on top of that texture, and so on.
    pass P0
    {        
        vertexshader = compile vs_2_0 vertexShader();
        pixelshader  = compile ps_2_0 pixelShader();
 
        Lighting     = False;
        CullMode     = None;
    }	
}